package com.gm.wj.service;

import com.alipay.api.AlipayApiException;
import com.alipay.api.AlipayClient;
import com.alipay.api.DefaultAlipayClient;
import com.alipay.api.domain.AlipayTradeRefundModel;
import com.alipay.api.request.AlipayTradeFastpayRefundQueryRequest;
import com.alipay.api.request.AlipayTradeRefundRequest;
import com.alipay.api.response.AlipayTradeFastpayRefundQueryResponse;
import com.alipay.api.response.AlipayTradeRefundResponse;
import com.gm.wj.config.AlipayConfig;
import com.gm.wj.entity.*;
import com.gm.wj.util.MyTime;
import com.gm.wj.util.SendByEmailTools;
import com.gm.wj.util.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;

/**
 * @program: wj
 * @description: 退款的操作
 * @author: Huang_shengjun
 * @create: 2020-11-23 12:17
 **/
@Slf4j
@Service
public class AliPayService {

    @Autowired
    SysOrderFlowService sysOrderFlowService;
    @Autowired
    PtService ptService;
    @Autowired
    UserService userService;
    @Autowired
    SysCourseService sysCourseService;
    @Autowired
    SysMessageService sysMessageService;

//    public static void main(String[] args) {
//        //订单编号,支付宝交易号不为空
//        String tradeNo = "2020112122001455300501000908";  // 支付宝交易号
//        String outTradeNo = "20201121105305731000";  // 系统订单号
//        String outRequestNo = "20201121105326101001213213";  // 系统退款号
//        String refundAmount = "2";
//        String refundReason = "退款说明";
//
//        Map<String, String> map = aliRefund(tradeNo,outTradeNo,outRequestNo,refundAmount,refundReason);
//        if (map.get("code").equals("400")) {
//            log.info(map.get("message"));
//        }else if (map.get("code").equals("400")) {
//            log.info(map.get("message"));
//        }
//
//    }

    /**
     * 保存到流水账单公共方法
     * @param out_trade_no
     * @param trade_no
     */
    public int saveFlow(String out_trade_no, String trade_no, String buyer_pay_amount, int payType) {

        try {
            if (sysOrderFlowService.findByTradeNo(trade_no)) {
                log.info("👇👇👇保存到流水账单公共方法开始了");
                // 订单号
                SysOrder sysOrder = sysOrderFlowService.findSysOrderByOrderId(out_trade_no);

                SysFlow sysFlow = new SysFlow();
                sysFlow.setUsername(sysOrder.getUsername());
                sysFlow.setFlowId(StringUtils.generateOrderNo());
                sysFlow.setOrderId(sysOrder.getOrderId());
                sysFlow.setTrade_no(trade_no);// 设置支付宝交易号
                sysFlow.setProductId(sysOrder.getProductId());
                sysFlow.setPayAmount(sysOrder.getOrderAmount());
                if (payType == 0) {
                    sysFlow.setPayMethod(0); // 支付方式：0-线上支付，1-现金支付
                    sysFlow.setIsPay(0); // 支付：0-线上支付成功；1-现金支付成功；2-退款
                } else if (payType == 1) {
                    sysFlow.setPayMethod(1); // 支付方式：0-线上支付，1-现金支付
                    sysFlow.setIsPay(1); // 支付：0-线上支付成功；1-现金支付成功；2-退款
                }

                sysFlow.setFlowDesc("无");
                sysFlow.setOutRequestNo("无");
                // 插入当前时间
                sysFlow.setCreateTime(MyTime.getStringDate());
                log.info("👇👇👇输出2===》"+sysFlow.toString());
                // 保存流水单信息 保存到数据库
                sysOrderFlowService.addFlow(sysFlow);

                // 更改订单信息
                sysOrder.setOrderStatus(1);
                sysOrder.setPayAmount(buyer_pay_amount);
                sysOrder.setPayTime(MyTime.getStringDate());
                log.info("👇👇👇输出3===》"+sysOrder.toString());
                // 更改订单信息
                sysOrderFlowService.editOrder(sysOrder);
                User user = userService.findByUsername(sysOrder.getUsername());
                SysCourse sysCourse = sysCourseService.findByCourseId(sysOrder.getProductId());
                try{
                    sysMessageService.sendMailToOrder(user.getUsername(),sysOrder.getOrderId(),user.getEmail(),sysFlow.getCreateTime(),sysCourse.getCourseName(),sysCourse.getTeacher(),sysFlow.getPayAmount());
                } catch (Exception e) {
                    log.error(e.getMessage());
                } finally {
                    // 根据订单id 查询开团订单id是否存在
                    PtCaptain ptCaptain = ptService.findCaptainByOrderId(out_trade_no);
                    if (ptCaptain != null && ptCaptain.getPtStatus() == 0){
                        // 存在订单,设置为支付成功 0:未付款 1:拼团中，2:拼团成功, 3：拼团失败
                        log.info("0:未付款的发起拼团的订单支付成功，正在设置“拼团中”。让其他人看到拼团-->{}",ptCaptain.toString());
                        // Redis监听到了发起拼团的订单失效，设置拼团状态 0:未付款 1:拼团中，2:拼团成功, 3：拼团失败
                        ptService.setPtCaptainStatus(ptCaptain.getId(),1);
                        // 支付成功之后，Redis 开始正式倒计时拼团订单
                        ptService.setRedisStartByPt(ptCaptain.getFatherId());
                    }

                    PtMember ptMember = ptService.findMemberByOrderId(out_trade_no);
                    // 根据订单id 查询参团订单id是否存在
                    if (ptMember != null && ptMember.getPtStatus() == 0){
                        log.info("流水生成中----存在参团订单？ {}",ptMember.toString());
                        // 存在订单,设置为支付成功 0:未付款 1:加团成功 2;超时
                        log.info("参与拼团的订单支付成功，正在设置“1:加团成功”。-->{}",ptMember.toString());
                        ptService.setPtMemberStatus(ptMember.getId(),1);
                    }
                    return 1;
                }
            }
            return 2; // 已经存在订单流水了
        }catch (Exception e){
            e.printStackTrace();
            return 0;
        }
    }


    /**
     * 退款操作：
     * 退款成功注意事项。
     全额退款情况：trade_status= TRADE_CLOSED，而refund_status=REFUND_SUCCESS；
     非全额退款情况：trade_status= TRADE_SUCCESS，而refund_status=REFUND_SUCCESS
     * @param aliPayAccountData
     * @param tradeNo      支付宝订单交易号
     * @param outTradeNo   本系统生成的商户订单编号
     * @param outRequestNo 标识一次退款请求，同一笔交易多次退款需要保证唯一，如需部分退款，则此参数必传。
     * @param refundAmount 退款金额 不得大于订单金额
     * @param refundReason 退款说明
     * @return 公共返回参数 code,msg,   响应参数实例: https://docs.open.alipay.com/api_1/alipay.trade.refund
     * @return
     */
    public Map<String,String> aliRefund(String tradeNo, String outTradeNo, String outRequestNo, String refundAmount, String refundReason) {
        Map<String, String> map = new HashMap<String, String>();
        log.info("【退款】支付宝进行退款操作********");
        AlipayClient alipayClient = getAliPayClient();

        if (outTradeNo != null && tradeNo != null) {
            AlipayTradeRefundRequest aliPayRequest = new AlipayTradeRefundRequest();
            AlipayTradeRefundModel model = new AlipayTradeRefundModel();
            model.setOutTradeNo(outTradeNo);
            model.setTradeNo(tradeNo);
            model.setRefundAmount(refundAmount);
            model.setRefundReason(refundReason);
            model.setOutRequestNo(outRequestNo);
            aliPayRequest.setBizModel(model);
            try {
                AlipayTradeRefundResponse aliPayResponse = alipayClient.execute(aliPayRequest);
                log.info("【退款】支付宝退款结果展示aliPayResponse:  {}", aliPayResponse.getBody());

                /**  这里的退款操作，支付宝提示： 支付宝退款失败，买家状态非法，无法继续交易
                 *   未找到原因，先避开支付宝回调。直接设置它退款成功
                 *   后续退款回调正常了再松开下面的注释
                log.info("【退款】支付宝退款成功");
                map.put("code", "200");
                map.put("message", "【退款】支付宝退款成功，提示：" + aliPayResponse.getSubMsg());
                return map;
                 */
                /** 松开下面的注释 **/
                if("10000".equals(aliPayResponse.getCode())){
                    log.info("【退款】支付宝退款成功");
                    map.put("code", "200");
                    map.put("message", "【退款】支付宝退款成功，提示：" + aliPayResponse.getSubMsg());
                    return map;
                } else if (!"10000".equals(aliPayResponse.getCode())) {
                    log.info("【退款】支付宝退款失败，支付宝交易号：{}，状态码：{}", tradeNo, aliPayResponse.getCode());
                    map.put("code", "400");
                    map.put("message","【退款】支付宝退款失败，提示："+ aliPayResponse.getSubMsg());
                    return map;
                }
            } catch (AlipayApiException e) {
                e.printStackTrace();
                map.put("code", "400");
                map.put("message", e.getMessage());
                return map;
            }
        }
        map.put("code", "400");
        map.put("message", "订单不存在");
        return map;
    }

    /**
     * 查询退款信息
     * @param outTradeNo   本系统生成的商户订单编号
     * @param tradeNo      支付宝订单交易号
     * @param outRequestNo 标识一次退款请求，同一笔交易多次退款需要保证唯一，如需部分退款，则此参数必传。
     * @return
     */
    public static void aliRefundQuery(String tradeNo,String outTradeNo,String outRequestNo) {
        log.info("【退款查询】支付宝退款详情操作********");
        try {

            AlipayClient alipayClient = getAliPayClient();
            AlipayTradeFastpayRefundQueryRequest request = new AlipayTradeFastpayRefundQueryRequest();
            request.setBizContent("{" +
                    "\"trade_no\":\"" + tradeNo + "\"," +
                    "\"out_trade_no\":\"" + outTradeNo + "\"," +
                    "\"out_request_no\":\"" + outRequestNo + "\" " +
                    "  }");
            AlipayTradeFastpayRefundQueryResponse response = alipayClient.execute(request);
            if(response.isSuccess()){
                System.out.println("【退款查询】调用成功");
            } else {
                System.out.println("【退款查询】调用失败");
            }
            //输出
            log.info("【退款查询】查询支付宝退款-->成功code：{}--返回信息：{}--trade_no:{}--out_trade_no:{}--getTotalAmount:{}--getRefundAmount:{}", response.getCode(),response.getMsg(),response.getTradeNo(),
                    response.getOutTradeNo(),response.getTotalAmount(),response.getRefundAmount());
        } catch (AlipayApiException e) {
            log.error("【退款查询】查询支付宝退款异常：", e);
        }
    }

    /**
     * 获取支付宝Client
     *
     * @return
     */
    private static AlipayClient getAliPayClient() {
        return new DefaultAlipayClient(
                AlipayConfig.URL, AlipayConfig.APPID, AlipayConfig.RSA_PRIVATE_KEY, AlipayConfig.FORMAT,
                AlipayConfig.CHARSET, AlipayConfig.ALIPAY_PUBLIC_KEY, AlipayConfig.SIGNTYPE);
    }


}
